Анализ рынка общественного питания¶

Оглавление

  • 1  Импорт библиотек и данных
  • 2  Предобработка данных
    • 2.1  Основные сведения
    • 2.2  Проверка на дубликаты
    • 2.3  Проверка названий заведений
    • 2.4  Проверка категорий
    • 2.5  Адреса
    • 2.6  Время работы
    • 2.7  Работа с пропусками
    • 2.8  Вывод
  • 3  Анализ данных
    • 3.1  Функции
    • 3.2  Категория заведений
    • 3.3  Количество посадочных мест по категории
    • 3.4  Соотношение сетевых заведений
    • 3.5  Категории сетевых заведений
    • 3.6  ТОП - 15 сетевых заведений города Москвы
    • 3.7  Заведения по административным округам Москвы
    • 3.8  Средний рейтинг по категориям заведений
    • 3.9  Фоновая картограма с рейтенгом заведений в районе
    • 3.10  Карта всех заведений
    • 3.11  ТОП-15 улиц по количеству заведений
    • 3.12  Улица с 1 заведением
    • 3.13  Средний чек по округам
    • 3.14  Режим работы заведений
    • 3.15  Вывод по разделу
  • 4  Открытие кофейни
    • 4.1  Количество кофеен и расположение
    • 4.2  График работы кофейн
    • 4.3  Средняя цена чашки кофе
    • 4.4  Рекомендации
  • 5  Презентация

Первая часть задания¶

Для крупного инвестиционного фонда «Shut Up and Take My Money» нужно провести исследование рынка в области общественного питания города Москвы для выявления интересных особенностей и закономерностей которые в будущем помогут в выборе подходящего инвесторам места.


Задача:

  • Исследовать рынок общественного питания города Москвы;
  • Найти особенности и закономерности в полученных данных;
  • Определить тип заведения;
  • Определить локацию места;
  • Определить кухню;
  • Определить ценовую категорю.

Исходные данные:
Датасет с заведениями общественного питания Москвы, составленный на основе данных сервисов Яндекс Карты и Яндекс Бизнес на лето 2022 года. Информация, размещённая в сервисе Яндекс Бизнес, могла быть добавлена пользователями или найдена в общедоступных источниках. Она носит исключительно справочный характер.


Описание данных

  • name — название заведения;
  • address — адрес заведения;
  • category — категория заведения, например «кафе», «пиццерия» или «кофейня»;
  • hours — информация о днях и часах работы;
  • lat — широта географической точки, в которой находится заведение;
  • lng — долгота географической точки, в которой находится заведение;
  • rating — рейтинг заведения по оценкам пользователей в Яндекс Картах (высшая оценка — 5.0);
  • price — категория цен в заведении, например «средние», «ниже среднего», «выше среднего» и так далее;
  • avg_bill— строка, которая хранит среднюю стоимость заказа в виде диапазона, например:
    • «Средний счёт: 1000–1500 ₽»;
    • «Цена чашки капучино: 130–220 ₽»;
    • «Цена бокала пива: 400–600 ₽». и так далее;
  • middle_avg_bill — число с оценкой среднего чека, которое указано только для значений из столбца avg_bill, начинающихся с подстроки «Средний счёт»:
    • Если в строке указан ценовой диапазон из двух значений, в столбец войдёт медиана этих двух значений.
    • Если в строке указано одно число — цена без диапазона, то в столбец войдёт это число.
    • Если значения нет или оно не начинается с подстроки «Средний счёт», то в столбец ничего не войдёт.
  • middle_coffee_cup — число с оценкой одной чашки капучино, которое указано только для значений из столбца avg_bill, начинающихся с подстроки «Цена одной чашки капучино»:
    • Если в строке указан ценовой диапазон из двух значений, в столбец войдёт медиана этих двух значений.
    • Если в строке указано одно число — цена без диапазона, то в столбец войдёт это число.
    • Если значения нет или оно не начинается с подстроки «Цена одной чашки капучино», то в столбец ничего не войдёт.
  • chain — число, выраженное 0 или 1, которое показывает, является ли заведение сетевым (для маленьких сетей могут встречаться ошибки):
    • 0 — заведение не является сетевым
    • 1 — заведение является сетевым
  • district — административный район, в котором находится заведение, например Центральный административный округ;
  • seats — количество посадочных мест.

Вторая часть задания¶

Основателям фонда «Shut Up and Take My Money» принял решение — открыть кофейню в Москве. Заказчик осознает полноту данных о существующей конкуренции на рынке и не боятся её в этой сфере, ведь кофеен в больших городах уже достаточно.

Нужно определить:

  • Количество кофеен;
  • Режим работы;
  • Рейтинги и их распределение по округам;
  • На среднюю цену за чашку ароматного кофе.

Импорт библиотек и данных¶

Для корректной работы кластеров библиотеки plotly установим пакет обновлений

In [1]:
pip install plotly==5.13.1
Requirement already satisfied: plotly==5.13.1 in /Users/user/opt/anaconda3/lib/python3.9/site-packages (5.13.1)
Requirement already satisfied: tenacity>=6.2.0 in /Users/user/opt/anaconda3/lib/python3.9/site-packages (from plotly==5.13.1) (8.0.1)
Note: you may need to restart the kernel to use updated packages.
In [2]:
# Импорт библиотек
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import plotly.express as px 
import plotly.graph_objects as go
import json
from urllib.request import urlopen
In [3]:
# Загрузим границы административных округов 
with urlopen('https://code.s3.yandex.net/data-analyst/admin_level_geomap.geojson') as f:
    geo_json = json.load(f)
In [4]:
# Импорт данных
data = pd.read_csv('https://code.s3.yandex.net/datasets/moscow_places.csv')

Предобработка данных¶

Основные сведения¶

In [5]:
# Выведем основную информацию о файле
display(data.info())
data.head()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 8406 entries, 0 to 8405
Data columns (total 14 columns):
 #   Column             Non-Null Count  Dtype  
---  ------             --------------  -----  
 0   name               8406 non-null   object 
 1   category           8406 non-null   object 
 2   address            8406 non-null   object 
 3   district           8406 non-null   object 
 4   hours              7870 non-null   object 
 5   lat                8406 non-null   float64
 6   lng                8406 non-null   float64
 7   rating             8406 non-null   float64
 8   price              3315 non-null   object 
 9   avg_bill           3816 non-null   object 
 10  middle_avg_bill    3149 non-null   float64
 11  middle_coffee_cup  535 non-null    float64
 12  chain              8406 non-null   int64  
 13  seats              4795 non-null   float64
dtypes: float64(6), int64(1), object(7)
memory usage: 919.5+ KB
None
Out[5]:
name category address district hours lat lng rating price avg_bill middle_avg_bill middle_coffee_cup chain seats
0 WoWфли кафе Москва, улица Дыбенко, 7/1 Северный административный округ ежедневно, 10:00–22:00 55.878494 37.478860 5.0 NaN NaN NaN NaN 0 NaN
1 Четыре комнаты ресторан Москва, улица Дыбенко, 36, корп. 1 Северный административный округ ежедневно, 10:00–22:00 55.875801 37.484479 4.5 выше среднего Средний счёт:1500–1600 ₽ 1550.0 NaN 0 4.0
2 Хазри кафе Москва, Клязьминская улица, 15 Северный административный округ пн-чт 11:00–02:00; пт,сб 11:00–05:00; вс 11:00... 55.889146 37.525901 4.6 средние Средний счёт:от 1000 ₽ 1000.0 NaN 0 45.0
3 Dormouse Coffee Shop кофейня Москва, улица Маршала Федоренко, 12 Северный административный округ ежедневно, 09:00–22:00 55.881608 37.488860 5.0 NaN Цена чашки капучино:155–185 ₽ NaN 170.0 0 NaN
4 Иль Марко пиццерия Москва, Правобережная улица, 1Б Северный административный округ ежедневно, 10:00–22:00 55.881166 37.449357 5.0 средние Средний счёт:400–600 ₽ 500.0 NaN 1 148.0

Комментарий:

  • В исходных данных содержаться 8406 строк;
  • Основные поля содержащие информацию о названии, категории, адресу, геопозиции, рейтингу не имеют пропусков.

Проверка на дубликаты¶

In [6]:
# Проверим данные на явные дубликаты
data.duplicated().sum()
Out[6]:
0

Комментарий:

  • Явные дубликаты в данных отсутствуют.

Проверка названий заведений¶

In [7]:
# Кол-во уникальных названий
data.name.sort_values().nunique()
Out[7]:
5614
In [8]:
# Приведем названия к нижнему регистру 
data.name = data.name.str.lower()
# Проверим количество уникальных названий
data.name.nunique()
Out[8]:
5512

Коменнтарий:

  • Всего в данных 5512 уникальных названий заведений;
  • На 102 уникальных названия стало меньше, за счет приведения к нижнему регистру.

Проверка категорий¶

In [9]:
print(*data.category.sort_values().unique().tolist(), sep='\n')
бар,паб
булочная
быстрое питание
кафе
кофейня
пиццерия
ресторан
столовая
In [10]:
data.category.nunique()
Out[10]:
8

Комментарий:

Всего 8 категорий:

  • бар,паб
  • булочная
  • быстрое питание
  • кафе
  • кофейня
  • пиццерия
  • ресторан
  • столовая

Проверим какие у какой сети сколько ресторанов в каждой категории

In [11]:
# Группируем по названию сети и категории и считаем кол-во заведений для каждой категории 
df = data.groupby(['name', 'category'], as_index=False).agg({'address':'count'})
# Посчитем общее число заведений для каждой сети 
df['count'] = df.groupby('name')['address'].transform('sum')
# Посчитаем количество категорий для каждой сети
df['count_name_cat'] = df.groupby('name')['category'].transform('count')
df['proc'] = df['address'] / df['count']
df.columns = ['Название сети', 'Категория', 'Кол-во по категории', 
              'Общее кол-во', 'Кол-во категорий', 'Доля от сети']

# Выведим результаты 
df[(df['Кол-во категорий'] > 2) & (df['Общее кол-во'] > 10)]\
.sort_values(['Общее кол-во','Кол-во по категории'], ascending=False)\
.style.format({'Доля от сети': '{:.1%}'}).background_gradient(subset=['Доля от сети'])
Out[11]:
  Название сети Категория Кол-во по категории Общее кол-во Кол-во категорий Доля от сети
3038 кафе кафе 159 189 7 84.1%
3041 кафе ресторан 8 189 7 4.2%
3037 кафе быстрое питание 7 189 7 3.7%
3039 кафе кофейня 6 189 7 3.2%
3042 кафе столовая 6 189 7 3.2%
3036 кафе бар,паб 2 189 7 1.1%
3040 кафе пиццерия 1 189 7 0.5%
5393 хинкальная кафе 19 44 5 43.2%
5394 хинкальная ресторан 15 44 5 34.1%
5392 хинкальная быстрое питание 6 44 5 13.6%
5391 хинкальная бар,паб 3 44 5 6.8%
5395 хинкальная столовая 1 44 5 2.3%
5755 шаурма быстрое питание 32 43 3 74.4%
5756 шаурма кафе 10 43 3 23.3%
5754 шаурма булочная 1 43 3 2.3%
5526 чайхана кафе 26 37 3 70.3%
5527 чайхана ресторан 9 37 3 24.3%
5525 чайхана быстрое питание 2 37 3 5.4%
2221 буханка булочная 25 32 3 78.1%
2223 буханка кофейня 6 32 3 18.8%
2222 буханка кафе 1 32 3 3.1%
3913 му-му кафе 12 27 7 44.4%
3916 му-му ресторан 8 27 7 29.6%
3912 му-му быстрое питание 2 27 7 7.4%
3914 му-му кофейня 2 27 7 7.4%
3911 му-му бар,паб 1 27 7 3.7%
3915 му-му пиццерия 1 27 7 3.7%
3917 му-му столовая 1 27 7 3.7%
3450 крошка картошка быстрое питание 20 22 3 90.9%
1921 андерсон кафе 17 22 3 77.3%
1923 андерсон ресторан 4 22 3 18.2%
1922 андерсон кофейня 1 22 3 4.5%
3451 крошка картошка кафе 1 22 3 4.5%
3452 крошка картошка ресторан 1 22 3 4.5%
661 french bakery кафе 17 20 3 85.0%
4814 скалка булочная 15 20 4 75.0%
4816 скалка кофейня 3 20 4 15.0%
662 french bakery кофейня 2 20 3 10.0%
660 french bakery булочная 1 20 3 5.0%
4815 скалка кафе 1 20 4 5.0%
4817 скалка пиццерия 1 20 4 5.0%
1762 wild bean cafe кофейня 8 16 3 50.0%
1761 wild bean cafe кафе 7 16 3 43.8%
1760 wild bean cafe быстрое питание 1 16 3 6.2%
3205 кафетерий кафе 11 15 3 73.3%
3204 кафетерий быстрое питание 2 15 3 13.3%
3206 кафетерий столовая 2 15 3 13.3%
2105 бистро кафе 6 12 4 50.0%
2104 бистро быстрое питание 4 12 4 33.3%
2102 бистро бар,паб 1 12 4 8.3%
2103 бистро булочная 1 12 4 8.3%

Комментарий:

  • Сеть с названием "Кафе" (наверное самое популярное название и его использует все кто не лень) насчитывает 189 заведений и имеет 7/8 категорий, не хватает только кафе с в категории булочная, но почти 84% находится в категории кафе, справедливость торжествует.
  • Остальные названия заведения так же имеют разнообразные категории, но в основном (60% и более) одно название занимает одну категорию, а оставшийся процент делится на остальные категории. Скорее всего это связано с тем, что категорию заведения могут добавлять пользователи и могут допускать определенные ошибки.

Адреса¶

In [12]:
# Приведем все в нижний регистр
data.address = data.address.str.lower()
# Добавим столбец с адресами
data['street'] = data.address.str.split(', ').str[1]
# Добавим столбец с гордами 
data['city'] = data.address.str.split(', ').str[0]
# Посчитаем кол-во уникальных улиц
data.street.nunique()
Out[12]:
1447
data['address'].str.split(', ').str[1]
In [13]:
# Посчитаем кол-во уникальных городов
data.city.nunique()
Out[13]:
1

Комментарий

  • В наших данных 1447 уникальных названий улиц и один город Москва

Время работы¶

In [14]:
# Приведем все в нижний регистр 
data.hours.str.lower()
# Добавим столбец с булевымы значениями
data['clock'] = data.hours.str.contains('ежедневно, круглосуточно', regex=False, na=False)

Работа с пропусками¶

In [15]:
# Найдем пропуски
df = data.isna().sum().reset_index()
# Добавим общее кол-во записей
df['all'] = data.shape[0]
df.columns = ['Col', 'items', 'all']
# Посчитаем долю
df['proc'] = df['items'] / df['all']
df.sort_values('items', ascending=False).head(10).style.format({'proc': '{:.2%}'})\
.background_gradient(subset=['proc'])
Out[15]:
  Col items all proc
11 middle_coffee_cup 7871 8406 93.64%
10 middle_avg_bill 5257 8406 62.54%
8 price 5091 8406 60.56%
9 avg_bill 4590 8406 54.60%
13 seats 3611 8406 42.96%
4 hours 536 8406 6.38%
15 city 0 8406 0.00%
14 street 0 8406 0.00%
12 chain 0 8406 0.00%
0 name 0 8406 0.00%
In [16]:
# Пропуски кол-ва посадочных мест для категорий
(data[data['seats'].isna() == True].groupby('category', as_index=False)['name']
 .count().sort_values('name', ascending=False))
Out[16]:
category name
3 кафе 1160
6 ресторан 773
4 кофейня 662
0 бар,паб 297
2 быстрое питание 254
5 пиццерия 206
7 столовая 151
1 булочная 108
In [17]:
# Пропуски кол-ва посадочных мест для категории ресторан
(data[(data['seats'].isna() == True) & (data['category'] =='ресторан')]
 .groupby('name', as_index=False)['address']
 .count().sort_values('address', ascending=False)).head(10)
Out[17]:
name address
636 яндекс лавка 34
140 prime 17
543 теремок 10
288 джонджоли 7
530 сушистор 7
405 моремания 7
536 татнефть кафе 5
329 кафе 5
466 ресторан 4
173 vasilchukí chaihona №1 4
In [18]:
# Проверим содержиться ли информация в middle_avg_bill взятая из avg_bill
data[(data.avg_bill.isna() == False) & 
     (data.middle_avg_bill.isna() == True) & 
     (data.avg_bill.str.contains('Средний счёт:', regex=False) == True)]\
    ['middle_avg_bill'].count()
Out[18]:
0

Средний чек перенесен полностью, пропуски отсутствуют.

In [19]:
# Проверим содержиться ли информация в middle_avg_bill взятая из avg_bill
data[(data.avg_bill.isna() == False) & 
     (data.middle_coffee_cup.isna() == True) & 
     (data.avg_bill.str.contains('чашки', regex=False) == True)]\
    ['middle_coffee_cup'].count()
Out[19]:
0

Цена чашки кофе перенесена полностью, пропуски отсутствуют.

Комментарий:

  • 6.4% имеют пустые поля в режиме работы - оставим данные как есть.
  • 42.9% заведений имеют пропуски в кол-ве посадочных мест.
    • 1160 кафе, 773 ресторана, 662 кофейни и т.д.
    • Кол-во посадочных мест актуально размещать там где проводятся банкеты.
    • Возьмем рестораны где более актуальная данная информация видно что на мерповм месте Яндекс Лавка, prime, теремок - у этих заведений скорее всего не правильно выставлена категория.
    • Что бы не исказить существующие данные лучше оставить как все есть.
  • 60.5% пропусков в категории прайс - оценка субъективная, для кого-то может дорого для кого-то нет, зависит от вида заведения его места кухни и многих других параметров, которые оценить по этим данным не возможно, по этому оставим данные как есть
  • 54.6% avg_bill - так же оставим с пропуском, заполнение медданными данными может исказить выводы.
  • Пропуски в middle_avg_bill и middle_coffee_cup не связаны с переносом данных из avg_bill. данные не указаны на страницах заведения, заполнять медданными значениями может исказить существующие данные.

Вывод¶

В результате импорта и предобработки данных было выполнено:

  • Импортирован файл содержащий 8406 и 14 колонок;
  • Обнаружено 0 явных дубликатов.
  • Приведено название заведений в нижний регистр, что позволило убрать 102 неявных дубликата в названиях заведения;
  • Добелен столбец с названием улиц;
  • Добавлен бурливый столбец режима работы 24 часа;
  • Анализ пропусков показал что, заполнить данные медленным значениями будет не корректно.

Анализ данных¶

Функции¶

Напишем функции для построения графиков

In [20]:
# График БАР
def chart_bar(df, x, y, text, title, xa='', ya='', color=None, legend=None, yaxis=None):
    fig_bar = px.bar(df, x=x, y=y, text=text, color=color)

    fig_bar.update_layout(title=title,
                           xaxis_title = xa,
                           yaxis_title = ya,
                           legend_title=legend, 
                           yaxis=yaxis)
    fig_bar.show()
In [21]:
# График Pie
def chart_pie(labels, values, title, pull=[0.0]):
    fig_pie = go.Figure(data=[go.Pie(labels=labels, 
                             values=values, 
                             pull=pull,
                             textinfo='label+percent')])
    fig_pie.update_layout(width=600,
                          height=600,
                          margin=dict(l=100, r=0, t=50, b=0),
                          title=title)
    fig_pie.update_traces(showlegend=False)
    fig_pie.show()
In [22]:
# График Heatmap
def chatr_heatmap(df, title, xa = '', ya = ''):
    fig_heat = px.imshow(df, text_auto=True, aspect="auto")
    fig_heat.update_layout(title=title, xaxis_title = xa, yaxis_title = xa)
    fig_heat.show()
In [23]:
# функция построения карты по районам
def geo_hit_map(df, locations, color, title, labels={'name':'Кол-во', 'district':'Наименование округа'}):
    map_h = px.choropleth_mapbox(df, 
                               geojson=geo_json,
                               locations=locations,
                               color=color,
                               color_continuous_scale="blugrn",
                               featureidkey="name",
                               mapbox_style="carto-positron",
                               zoom=8.5, center = {"lat": 55.7522, "lon": 37.6156}, opacity=0.5,
                               labels=labels)

    map_h.update_layout(margin={"r":0,"t":50,"l":0,"b":0}, title=title)
    map_h.show()

Категория заведений¶

Подсчитаем количество заведений по категориям и построим графики для визуальной оценки их распределения.

In [24]:
# Считаем количество заведений по категориям
cat_hist = (data.groupby('category', as_index=False)['name']
            .count().sort_values('name', ascending=False).reset_index(drop=True))

cat_hist.columns = ['Категория', 'Кол-во']


# Строим гистограмму 
chart_bar(cat_hist, 'Категория', 'Кол-во', 'Кол-во', 'Самое большое количество заведений это КАФЕ',
         'Категория', 'Кол-во')

# Строим график pie с процентным соотношением  
chart_pie(cat_hist['Категория'], cat_hist['Кол-во'], 'Доля кафе самая большая', [0.1])

# pivot table for heatmap Кол-во заведений по округам
pt_1 = data.pivot_table(index='district', columns='category', values='name', aggfunc='count')

# heatmap 
chatr_heatmap(pt_1, 'Кол-во заведений по округам', 'Категория', 'Округ')

# pivot table for heatmap Медианная оценка по округам
pt_2 = data.pivot_table(index='district', columns='category', values='rating',aggfunc='median')

chatr_heatmap(pt_2, 'Медианная оценка по округам', 'Категория', 'Округ')

print(f'''Всего {data["name"].count()} заведений 
в {data.category.nunique()} категориях''')
Всего 8406 заведений 
в 8 категориях

Комментарий:

  • Всего 8406 заведений;
  • 8 категорий;
  • Лидерами можно выделить 3 категории на которые приходится 69.4% всех заведений:
    • Кафе с относительным значением 28.3% и абсолютным 2378;
    • Рестораны с относительным значением 24.3% и абсолютным 2043;
    • Кофейни с относительным значением 16.8% и абсолютным 1413;
  • Наименьшие кол-во заведений приходится на:
    • Булочная и столовая чья доля не превышает 4%;
  • Больше всего заведений в Центральном округе;
  • Больше всего ресторанов в центральном округе;
  • Больше всего баров в центральном округе;
  • Самая высокая оценка у баров в Центральном и Запорном округе;
  • Хуже всего оценка у заведений быстрого питания.

Да как и следовало ожидать жители столицы предпочитают пить кофе и посещать кафе/рестораны на бизнес ланч.

Количество посадочных мест по категории¶

Посчитаем кол-во пропусков по категориям для посадочных мест и постоим графики распределения посадочных мест.

In [25]:
print('''


Из раздела 2.7 поле кол-во посадоычнх мест имеет 42.96% пропусков 
или 3611 заведения из 8406.''')
df_setats_pr = (data[data.seats.isna() == True]
                .groupby('category', as_index=False)['name'].count())
df_setats_npr = (data[data.seats.isna() == False]
                .groupby('category', as_index=False)['name'].count())
df_setats_all = data.groupby('category', as_index=False)['name'].count()

df_setats = (df_setats_all.merge(df_setats_pr, how='left', on='category')
             .merge(df_setats_npr, how='left', on='category'))
df_setats.columns = ['category', 'all', 'prop', 'not_prop']
df_setats = df_setats.sort_values('all', ascending=False)
df_setats['poroc'] = round(df_setats.prop / df_setats.not_prop * 100)


fig_set_prop = go.Figure(data=[
    go.Bar(name='Нет пропусков', x=df_setats.category, y=df_setats.not_prop),
    go.Bar(name='Есть пропуски', x=df_setats.category, y=df_setats.prop)
])

fig_set_prop.update_layout(title='В РЕСТОРАНАХ меньше всего пропусков',
                           yaxis_title = 'Кол-во заведений',
                           xaxis_title = 'Категория',
                           height=500)

fig_set_prop.update_layout(barmode='group')
fig_set_prop.show()


chart_bar(df_setats.sort_values('poroc'), 'category', 'poroc', 'poroc', 
          'Отношение пропусков к их отсутсвию', 'Категория', 'Процент')



# Постоим boxplot для посадоынх мест
fig_seats_box_all = px.box(data, y="seats", points="all", hover_data=['category', 'name'])

fig_seats_box_all.update_layout(title='75 посадочных мест - медианное значение',
                           yaxis_title = 'Кол-во',
                           xaxis_title = 'Все категории',
                           height=500)

fig_seats_box_all.show()


# Постоим boxplot для посадоынх мест с разбивкой на категории 
fig_seats_box_cat = px.box(data, y="seats", x='category', range_y=[-10, 400], hover_data=['name'])

fig_seats_box_cat.update_layout(title='Распределение посадочных мест по категориям',
                           yaxis_title = 'Кол-во',
                           xaxis_title = 'Категория',
                           height=500)
fig_seats_box_cat.add_hline(y=75, line_width=1, line_dash="dash", 
                            line_color="red", annotation_text="Общая медина")

fig_seats_box_cat.show()

sets = data[data.seats.isna() == False].copy()
sets['col_s'] = np.where(sets.seats < 100, '0-100',
                np.where(sets.seats < 200, '100-200',
                np.where(sets.seats < 300, '200-300',
                np.where(sets.seats < 500, '300-500',
                np.where(sets.seats < 800, '500-800',
                np.where(sets.seats < 1200, '800-1200','более 1200' ))))))
s_300_map = px.scatter_mapbox(sets,
                        lat='lat',
                        lon='lng',
                        mapbox_style="open-street-map",
                        zoom=8.7,
                        hover_name='name',
                        hover_data=['seats'],
                        color='col_s',
                        labels={'col_s':'Кол-во мест'})
s_300_map.update_layout(margin={"r":0,"t":50,"l":0,"b":0},
                           title='Карта посадочных мест',)
s_300_map.update_traces(
                      marker=dict(size=13))
s_300_map.show()


Из раздела 2.7 поле кол-во посадоычнх мест имеет 42.96% пропусков 
или 3611 заведения из 8406.
In [26]:
# Расчитаем 96 перецентель 
np.percentile(data[data.seats.isna() == False].seats, 96)
Out[26]:
350.0

Комментарий:

  • Из раздела 2.7 поле кол-во посадочных мест имеет 42.96% пропусков или 3611 заведения из 8406;
  • Доля пропусков для каждой категории меньше доли без пропусков;
  • Самая низкая доля пропусков у пиццерии;
  • Межквартильный размах для всех заведений по посадочным местам расположен от 40 до 140 мест;
  • Медиана посадочных равна 75;
  • Минимальное число посадочных мест 0;
  • Максимальное число посадочынх мес 1288;
  • По общему графику выбросами можно считать где количество посадочных мест более 290;
  • Если смотреть на графики по заведениям, то данные очень хорошо описывают положение по каждой категории;
  • Самое высокое медианное значение посадочных мест у заведений категории рестораны;
  • На графике 75 посадочных мест - медианное значение прекрасно видно что выброс в 1288 мест есть у нескольких заведений, это ошибка ввода данных, такое количество мест может быть скорее всех на огромных фду кортах.
  • Всего 4% процента заведений имеют более 350 посадочных мест.

Соотношение сетевых заведений¶

Ресторанная сеть - это наличие нескольких предприятий общественного питания, которые могут охватывать и как региональный, так и международный рынки. Обычно, называют число три или пять. То есть три или пять заведений – это уже сеть. Примем в расчет, что 5 заведений это уже сеть.

In [27]:
# Посчитаем сколько раз каждое нзвание всетрчается раз
set_name = data.name.value_counts().reset_index()
# Уберем завдения встречающиеся менее 5 раз
set_name = set_name.query('name > 5')
# Переименуем колонки
set_name.columns = ['name', 'col']
# Посчитаем количество завведний
print('Количество уникальных сетевых заведений {}'.format(set_name.name.count()))
Количество уникальных сетевых заведений 107

Напишем имена которые явно не соответсвую сетевым

In [28]:
not_set = ['кафе', 'хинкальная', 'шаурма', 'чайхана', 'ресторан', 'столовая','донер кебаб', 'кафетерий', 
           'бистро', 'кофейня', 'кафе-столовая', 'кафе-бар', 'халяль', 'буфет', 'грузинская кухня',
           'трапезная', 'кофе', 'хачапури', 'донер', 'тандыр', 'шашлычная']
In [29]:
spisok = set_name.name.to_list()
spisok = np.setdiff1d(spisok, not_set).tolist()
len(spisok)
Out[29]:
86
In [30]:
data.query('name in @spisok').chain.value_counts()
Out[30]:
1    1494
0       8
Name: chain, dtype: int64

В Список попали 8 не сетевых заведений, посмотрим на них

In [31]:
data.query('name in @spisok and chain == 0').name.value_counts()
Out[31]:
star hit cafe       1
мск lounge          1
франклинс бургер    1
ля фантази          1
домино'с пицца      1
korean chick        1
one price coffee    1
burger club         1
Name: name, dtype: int64

Видим, что в данные закралась ошибка, все заведения сетевые

In [32]:
set_zaved = data.query('name in @spisok').name.count()
not_set_zaved = data.query('name not in @spisok').name.count()

chart_bar(df, ['Сетевое', 'Не сетеове'], 
              [set_zaved, not_set_zaved], [set_zaved, not_set_zaved], 
              'Рапределение сетевых заведений', 'Тип заведения', 'Кол-во')

chart_pie(['Сетевое', 'Не сетеове'], [set_zaved, not_set_zaved], 'Доля кафе самая большая', [0, 0.1])

Комментарий:

  • Доля сетевых заведений составила 18%, что равно 1510 заведений;
  • Доля не сетевых заведений составила 82%, что составило 6896 заведений.
  • В расчетах принято, что сетевое заведение - это кол-во заведений у одного имени более 5 и не название не соответствует таким как: кафе, шаурма и прочее.

Категории сетевых заведений¶

In [33]:
pt_3 = data.query('name in @spisok').category.value_counts().reset_index()

chart_bar(pt_3, 'index', 'category', 'category', 'Кофейня самое сетевое заведение', 'Тип заведения', 'Кол-во')

chart_pie(pt_3['index'], pt_3['category'], 'Доля кофейнь самая большая', pull=[0.1])

Комментарий:

  • В доле сетевых заведений первое место занимает кофейня ее доля составила 32% от всех сетевых заведений.
  • 85% всех сетевых заведений приходится на:
    • Кофейни - 32%;
    • Рестораны - 22.4%;
    • Пиццерии - 16.4%;
    • Кафе - 15.5;

ТОП - 15 сетевых заведений города Москвы¶

In [34]:
data.name.value_counts().reset_index().head(15)
Out[34]:
index name
0 кафе 189
1 шоколадница 120
2 домино'с пицца 77
3 додо пицца 74
4 one price coffee 72
5 яндекс лавка 69
6 cofix 65
7 prime 50
8 хинкальная 44
9 шаурма 43
10 кофепорт 42
11 кулинарная лавка братьев караваевых 39
12 теремок 38
13 чайхана 37
14 ресторан 34

В топ 15 входят заведения имя которых не принадлжит какой либо сети. Нужно их исключить. Так же входит сеть доставки Яндекс Лавка ее тоже убрем

In [35]:
top_15 = data.name.value_counts().reset_index().query('index != ["кафе", "хинкальная",\
        "шаурма", "чайхана", "столовая", "яндекс лавка", "ресторан"]').head(15)
top_15.columns = ['name', 'col']
top_15
Out[35]:
name col
1 шоколадница 120
2 домино'с пицца 77
3 додо пицца 74
4 one price coffee 72
6 cofix 65
7 prime 50
10 кофепорт 42
11 кулинарная лавка братьев караваевых 39
12 теремок 38
15 буханка 32
16 cofefest 32
18 му-му 27
19 drive café 24
20 кофемания 23
21 крошка картошка 22
In [36]:
chart_bar(top_15.sort_values('col'), 'col', 'name', 'col', 
          'ТОП-15 популярных сетей в Москве', 'Кол-во', 'Название сети')

top_15_cat =(data.query('name in @top_15.name.to_list()')
 .groupby(['name','category'], as_index=False)['address']
 .count())
top_15_cat['col'] = top_15_cat.groupby('name')['address'].transform('sum')
top_15_cat = top_15_cat.sort_values(['col', 'address'], ascending=False)

chart_bar(top_15_cat.sort_values('col'), 'address', 'name', None, 'Кофейни очень популярны', 
          'Кол-во', 'Категория', 'category', 'Заведение', {'categoryorder': 'total ascending'})

Комментарий:

  • В ТОП-15 сетевых заведений попали заведения явно не относящиеся к какой-либо сети, они были убраны;
  • 1 местов рейтинге заняла Шоколадница она насчитывает 120 заведений;
  • 2 и 3 место заняли пиццерии Доминос и Додо;
  • с 4 по 7 место разделяют сеть по приготовлению кофе;
  • Если рассматривать с точки зрения категории заведения то лидером безусловно являются кофейни их число в по всем сетям переваливает 350 заведений;
  • Большая часть заведений в категории кофейни принадлежит Шоколаднице;
  • Второе место достается пиццерии ее разделяют две сетевые фирмы Доминос и Додо;

Заведения по административным округам Москвы¶

In [37]:
# Загрузим границы административных округов 
with urlopen('https://code.s3.yandex.net/data-analyst/admin_level_geomap.geojson') as f:
    geo_json = json.load(f)
In [38]:
# Считаем заведения по округам
district = data.district.value_counts().reset_index()
district.columns = ['name', 'item']
district['proc'] = district.item / district.item.sum()

display(district.sort_values('item', ascending=False).style.format({'proc':'{:.2%}'}))

chart_bar(district, 'item', 'name', 'item', 'Центральный округ лидер по кол-ву заведений',
          'Кол-во', 'Округа', yaxis={'categoryorder': 'total ascending'})

# Строим карту по количесву заведений
geo_hit_map(district, 'name', 'item', 'Кол-во заведений по округам', {'item':'Кол-во', 'name':'Округ'})
  name item proc
0 Центральный административный округ 2242 26.67%
1 Северный административный округ 900 10.71%
2 Южный административный округ 892 10.61%
3 Северо-Восточный административный округ 891 10.60%
4 Западный административный округ 851 10.12%
5 Восточный административный округ 798 9.49%
6 Юго-Восточный административный округ 714 8.49%
7 Юго-Западный административный округ 709 8.43%
8 Северо-Западный административный округ 409 4.87%

Комментарий:

  • В Москве 9 окргуов;
  • 26.67% (2242) заведений располагаются в Центральном округе;
  • В Центральном округе в 2 раза больше заведений чем в любом другом;
  • Меньше всего заведений в Северо-Заподном округе 4.87% (409) заведений.

Средний рейтинг по категориям заведений¶

In [39]:
cat_rat = data.groupby('category', as_index=False).agg(median=('rating', 'median'),
          mean=('rating', 'mean')).sort_values('median', ascending=False)
cat_rat['mean'] = cat_rat['mean'].round(1)
display(cat_rat)

fig_box_cat_rat = px.box(data, y='category', x='rating')

fig_box_cat_rat.update_layout(title='Распределение рейтенгов заведений',
                         xaxis_title = 'Оценка',
                         yaxis_title = 'Категория',
                         yaxis={'categoryorder': 'total ascending'})
fig_box_cat_rat.add_vline(x=data.rating.median(), 
                            line_width=2, line_dash="dash", line_color="red",
                            annotation_text="Медиана по всем заведениям")

fig_box_cat_rat.show()
category median mean
0 бар,паб 4.4 4.4
1 булочная 4.3 4.3
4 кофейня 4.3 4.3
5 пиццерия 4.3 4.3
6 ресторан 4.3 4.3
7 столовая 4.3 4.2
2 быстрое питание 4.2 4.1
3 кафе 4.2 4.1

Комментарий:

  • Средний рейтинг всех заведений распределился от 4.2 до 4.4;
  • Среднее и медиана в 5/8 случаях совпадают в остальных случаях среднее ниже, что свидетельствуют о явных выбросах, которые видны на боксплоте;
  • Самый высокий рейтинг у баров, но учтем их доля среди всех заведений всего 9%;
  • Хуже всего дела у заведений быстрого питания 75% оценок у них ниже рейтинга 4.3;
  • Самые разнообразные оценки у категории кафе.

Фоновая картограма с рейтенгом заведений в районе¶

In [40]:
dist_rat = data.groupby('district', as_index=False)['rating'].median()

geo_hit_map(dist_rat, 'district', 'rating', 'Средняя оценка по округам', 
            labels={'rating':'Рейтинг','district':'Наименование округа'})

Комментарий:

  • Самая высокая средняя оценка (4.4) в Центральном округе;
  • Самая низкая средняя оценка (4.2) в Юго и Северо Восточных округах;
  • У остальных округов средняя оценка 4.3.

Карта всех заведений¶

In [41]:
all_map = px.scatter_mapbox(data,
                        lat='lat',
                        lon='lng',
                        mapbox_style="open-street-map",
                        zoom=8.7,
                        hover_name='name',
                        labels={'category':'Категория'})
all_map.update_layout(margin={"r":0,"t":50,"l":0,"b":0},
                           title='Все заведения',)
all_map.update_traces(cluster=dict(enabled=True, 
                               opacity=0.5,
                               size=8,
                               color='red',
                               maxzoom=13),
                      marker=dict(size=13))
all_map.show()

ТОП-15 улиц по количеству заведений¶

In [42]:
top_street = (data.query('street != "мкад"').street.value_counts().reset_index()
              .sort_values('street', ascending=False)
              .head(15))

top_street.columns = ['streets', 'item']

chart_bar(top_street, 'item', 'streets', 'item', 'TОП-15 улиц', 'Кол-во', 'Улицы', 
          yaxis={'categoryorder': 'total ascending'})

top_street_map = px.scatter_mapbox(data.query('street in @top_street.streets.unique()'),
                        lat='lat',
                        lon='lng',
                        mapbox_style="carto-positron",
                        color='street',
                        zoom=8.7,
                        hover_name='name',
                        hover_data=['street'],
                        labels={'street':'Улица'})
top_street_map.update_layout(margin={"r":0,"t":50,"l":0,"b":0},
                           title='ТОП-15 улиц',)
top_street_map.update_traces(
                      marker=dict(size=5))
top_street_map.show()

Комментарий:

  • На Проспекте Мира больше всего заведений, частично связанно с наличием большого парка ВДНХ.
  • Если принять за единое целое Ленинградский проспект и шоссе то второе место досталось бы ему.
  • Последнее место в ТОП-15 по кол-ву заведений достается Алтуфьевскому шоссе.
  • За счет того, что улицы длинные на них помещается очень много заведений, в том числе улицы вдоль которых идет метро.
  • Пятницкая улица хоть и занимает 14 место, но если провести расчет кол-во заведений на длину улицы она была один из лидеров.

Улица с 1 заведением¶

In [43]:
one_list_street = (data.street.value_counts().reset_index()
                   .query('street == 1')['index'].to_list())
one_street = data.query('street in @one_list_street')
print('Всего {} улиц с одним заведением'.format(len(one_list_street)))
print('Это {:.1%} от всех улиц'.format(len(one_list_street)/data.street.nunique()))
Всего 457 улиц с одним заведением
Это 31.6% от всех улиц
In [44]:
on_pt = (one_street.pivot_table(index=['district', 'category'], 
                       values=['name', 'rating', 'middle_avg_bill'], 
                       aggfunc={'name':'count', 
                                'rating':'median', 
                                'middle_avg_bill':'median'})
        .reset_index())
In [45]:
fig_on_pt = px.treemap(on_pt, path=[px.Constant("Москва"), 'district', 'category'], values='name',
                  color='rating', 
                  labels={'rating':'Рейтинг',
                          'labels':'Тип',
                          'parent':'Округ',
                          'name':'Кол-во'},
                  color_continuous_scale='RdBu')
                  #color_continuous_midpoint=np.average(df['rating'], weights=df['name']))
fig_on_pt.update_layout(
      title='Кол-во улиц с одним заведением по округам',
      margin=dict(t=50, l=25, r=25, b=25))
fig_on_pt.show()

Комментарий:

  • Больше всего улиц с одним заведением в Центральном округе;
  • Меньше всего улиц в Юго-Западном и Северо-Западном округе;
  • В Центральном округе у всех заведений высокий рейтинг;
  • Самые худшие рейтинги в Юго-Западном округе.

Средний чек по округам¶

In [46]:
dis_avg = data.groupby('district', as_index=False)['middle_avg_bill'].median()

geo_hit_map(dis_avg, 'district', 'middle_avg_bill', 'Средний чек в округе', 
            {'middle_avg_bill':'Средний чек','district':'Наименование округа'})

Комментарий:

  • В Центральном и Западном округе средний чек самый высокий 1000 руб;
  • Самый низкий средний чек в Юго-Восточном округе 450 рублей;
  • Чем восточнее от центра округ тем средний чек ниже.

Режим работы заведений¶

In [47]:
clock_24 = data.clock.value_counts().reset_index()

chart_pie(['Не круглосуточно', 'Круглосуточно'], clock_24.clock.to_list(), 'Режим работы', pull=[0.1])

clock = data[data.clock == True].pivot_table(index='district', columns='category', values='name',
                                     aggfunc='count').fillna(0)

chatr_heatmap(clock, 'Распределение круглосуточных заведений', 'Категория', 'Округ')

crt = data[data.clock == True].groupby('district')['name'].count().reset_index()

geo_hit_map(crt, 'district', 'name', 'Круглосуточные заведения', {'name':'Кол-во', 'district':'Наименование округа'})

Комментарий:

  • 8,68% или 730 заведения работают круглосуточно;
  • Большая часть (131 заведения) находится в Центральном округе;
  • Чем восточнее округ тем больше заведений работают круглосуточно.

Вывод по разделу¶

Общие сведения

  • Всего 8406 заведений;
  • 8 категорий;
  • Лидерами можно выделить 3 категории на которые приходится 69.4% всех заведений:
    • Кафе с относительным значением 28.3% и абсолютным 2378;
    • Рестораны с относительным значением 24.3% и абсолютным 2043;
    • Кофейни с относительным значением 16.8% и абсолютным 1413;
  • Наименьшие кол-во заведений приходится на:
    • Булочная и столовая чья доля не превышает 4%;
  • Больше всего заведений в Центральном округе;
  • Больше всего ресторанов и баров в Центральном округе;
  • Самая высокая оценка у баров в Центральном и Запорном округе;
  • Хуже всего оценка у заведений быстрого питания.

Количество посадочных мест:

  • 50% заведений имеет от 40 до 140 посадочных мест;
  • Медиана посадочных равна 75;
  • Всего 4% заведений имеют посадочных мест боле 350;

Доля сетевых заведений: В расчетах принято, что сетевое заведение - это кол-во заведений у одного имени более 5 и не название не соответствует таким как: кафе, шаурма и прочее.

  • Доля сетевых заведений составила 18%, что равно 1510 заведений;
  • Доля не сетевых заведений составила 82%, что составило 6896 заведений.
  • В доле сетевых заведений первое место занимает кофейня ее доля составила 32% от всех сетевых заведений;
  • 85% всех сетевых заведений приходится на:
    • Кофейни - 32%;
    • Рестораны - 22.4%;
    • Пиццерии - 16.4%;
    • Кафе - 15.5;

В ТОП-15 сетевых заведений:

  • 1 место в рейтинге заняла Шоколадница она насчитывает 120 заведений;
  • 2 и 3 место заняли пиццерии Доминос и Додо;
  • с 4 по 7 место разделяют сеть по приготовлению кофе;
  • Если рассматривать с точки зрения категории заведения то лидером безусловно являются кофейни их число в по всем сетям переваливает 350 заведений;
  • Большая часть заведений в категории кофейни принадлежит Шоколаднице;
  • Второе место достается пиццерии ее разделяют две сетевые фирмы Доминос и Додо;
  • В Москве 9 окргуов;
  • 26.67% (2242) заведений располагаются в Центральном округе;
  • В Центральном округе в 2 раза больше заведений чем в любом другом;
  • Меньше всего заведений в Северо-Заподном округе 4.87% (409) заведений.

Рейтинг:

  • Средний рейтинг всех заведений распределился от 4.2 до 4.4;
  • Самый высокий рейтинг у баров;
  • Хуже всего дела у заведений быстрого питания 75% оценок у них ниже рейтинга 4.3;
  • Самые разнообразные оценки у категории кафе.
  • Самая высокая средняя оценка (4.4) в Центральном округе;
  • Самая низкая средняя оценка (4.2) в Юго и Северо Восточных округах;
  • У остальных округов средняя оценка 4.3.

ТОП-15 улиц

  • На Проспекте Мира больше всего заведений, частично связанно с наличием большого парка ВДНХ.
  • Если принять за единое целое Ленинградский проспект и шоссе то второе место досталось бы ему.
  • Последнее место в ТОП-15 по кол-ву заведений достается Алтуфьевскому шоссе.

Улица с одним заведением:

  • Всего 457 улиц с один заведением общественного питания;
  • Больше всего улиц с одним заведением в Центральном округе;
  • Меньше всего улиц в Юго-Западном и Северо-Западном округе;
  • В Центральном округе у всех заведений высокий рейтинг;

Средний чек:

  • Самые худшие рейтинги в Юго-Западном округе.
  • В Центральном и Западном округе средний чек самый высокий 1000 руб;
  • Самый низкий средний чек в Юго-Восточном округе 450 рублей;
  • Чем восточнее от центра округ тем средний чек ниже.

Режим работы:

  • 8,68% или 730 заведения работают круглосуточно;
  • Большая часть (131 заведения) находится в Центральном округе;
  • Чем восточнее округ тем больше заведений работают круглосуточно.

Открытие кофейни¶

Количество кофеен и расположение¶

In [48]:
# Импортируем координаты метро
metro = pd.read_csv('https://github.com/VoytyukIlya/doc/blob/main/metro/624.csv?raw=true', 
                    sep=';', index_col=0,)
metro = metro[['STATION','X', 'Y']]
metro['X'] = metro['X'].str.replace(',','.')
metro['Y'] = metro['Y'].str.replace(',','.')
In [49]:
cof = data[data.category == 'кофейня']

print('Всего кофеен в городе Москва {} кофейн'.format(cof.name.count()))

cof_pt = cof.groupby('district', as_index=False)['name'].count()
cof_pt = cof_pt.sort_values('name')

chart_bar(cof_pt, 'name', 'district', 'name', 'Кол-во кофеен по округам', 'Кол-во', 'Округ')

geo_hit_map(cof_pt, 'district', 'name', 'Кол-во кофеен по округам', {'name':'Кол-во','district':'Наименование округа'})

fig = go.Figure()

fig.add_trace(go.Scattermapbox(
                        lat=cof.lat,
                        lon=cof.lng,
        mode='markers',
        marker=go.scattermapbox.Marker(
            size=6,
            color='rgb(255, 0, 0)',
            opacity=0.7
        ),
        text=cof.name,
        name='Кофейни'
    ))

fig.add_trace(go.Scattermapbox(
        lat=metro['Y'],
        lon=metro['X'],
        mode='markers',
        marker=go.scattermapbox.Marker(
            size=8,
            color='blue',
            opacity=0.7
        ),
        text=metro.STATION,
        name='Метро'
    ))

fig.update_layout(
    title='Расопложение относительно станций метро',
    autosize=True,
    hovermode='closest',
    showlegend=True,
    mapbox_style="open-street-map",
    margin={"r":0,"t":50,"l":0,"b":0},
    mapbox=dict(
        center=dict(
            lat=55.7522,
            lon=37.6156
        ), zoom=9))


fig.show()
Всего кофеен в городе Москва 1413 кофейн

Комментарий:

  • Всего 1413 кофейни.
  • Большая часть сосредоточена в центре;
  • 193 заведения расположены в центральном округе;
  • Меньше всего заведений в Северно-Заподном округе, скорее всего это связанно с маленькой площадью района и большой зеленой площадью;
  • Чем дальше заведения от центра города тем больше они концентрируются возле станций метро, жд-станций и территориях торговых центрах.

График работы кофейн¶

In [50]:
cof_1 = cof[cof.clock==True]
cof_pt_map_24 = px.scatter_mapbox(cof_1,
                        lat='lat',
                        lon='lng',
                        mapbox_style="open-street-map",
                        zoom=8.7,
                        hover_name='name',
                        hover_data=['hours'],
                        labels={'street':'Улица'})
cof_pt_map_24.update_layout(margin={"r":0,"t":50,"l":0,"b":0},
                           title='Круглосуточные кофейни',)
cof_pt_map_24.update_traces(
                      marker=dict(size=12))
cof_pt_map_24.show()

cof_pt_map_24_ch = px.scatter_mapbox(cof_1.query('name == "шоколадница"'),
                        lat='lat',
                        lon='lng',
                        mapbox_style="open-street-map",
                        zoom=8.7,
                        hover_name='name',
                        hover_data=['hours'],
                        labels={'street':'Улица'})
cof_pt_map_24_ch.update_layout(margin={"r":0,"t":50,"l":0,"b":0},
                           title='Круглосуточные Шоколадницы',)
cof_pt_map_24_ch.update_traces(
                      marker=dict(size=12, color='red'))
cof_pt_map_24_ch.show()

print('Всего круглосуточных кофейн {}'.format(cof_1.name.count()))
print('Из них Шоколадниц {}'.format(cof_1.query('name == "шоколадница"').name.count()))
Всего круглосуточных кофейн 59
Из них Шоколадниц 17

Комментарий:

  • Всего 76 круглосуточных кофейн;
  • Из них 33 относиться к сети Шоколадница;
  • Круглосуточные кофейни в большем количестве располагаются в центре города;
  • В чем дальше от центра тем меньше становиться кофейн и тем ближе они располагаются к оживленным улицам и проспектам.

Средняя цена чашки кофе¶

In [51]:
coffe_cup = px.box(data, x='category',
                   y='middle_coffee_cup',
                   range_y=[0, 400])
coffe_cup.update_layout(title='Распределение цен',
                           xaxis_title = 'Заведение',
                           yaxis_title = 'Цена')
coffe_cup.show()

cof_price = cof.groupby('district', as_index=False)['middle_coffee_cup'].median()

geo_hit_map(cof_price, 'district', 'middle_coffee_cup', 'Медианная цена по округам', 
            {'middle_coffee_cup':'Цена','district':'Наименование округа'})

cof_rat = cof.groupby('district', as_index=False)['rating'].mean()

geo_hit_map(cof_rat, 'district', 'rating', 'Рейтинг по округам', 
            {'rating':'Рейтинг', 'district':'Наименование округа'})

Комментарий:

  • Хоть что то не самое-самое в центральном округе;
  • Самая большая средняя цена за чашку кофе составит 198 рублей на Юго-Западе;
  • Самый недорогой средний кофе в Восточном округе;
  • В целом в кафейнях медианная цена за кофе 170 рублей, что ниже чем в барах, но выше чем в остальных категориях заведений.
  • Кофейни славиться большим выбором кофе ну и цены соответсвенно от 60-375 рублей.

Рекомендации¶

  • Всего 1413 кофейни.
  • Большая часть сосредоточена в центре (около 193 заведений);
  • Меньше всего заведений в Северно-Заподном округе, скорее всего это связанно с маленькой площадью района и большой зеленой площадью;
  • Чем дальше заведения от центра города тем больше они концентрируются возле станций метро, жд-станций и на территориях торговых центров.
  • Всего 76 круглосуточных кофейн;
  • Из них 33 относиться к сети Шоколадница;
  • Круглосуточные кофейни в большем количестве располагаются в центре города;
  • В чем дальше от центра тем меньше становиться кофейн и тем ближе они располагаются к оживленным улицам и проспектам.
  • Вкладываться в ночной бизнес не самая лучшая идея, кофе в большой частью пьют в дневное время суток, в ночное время есть другие заведения.
  • Самые низкие по рейтингам кофейни находятся в западном районе. Стоит избегать данный район, так как открывать большую кофейню изначально - не очень хорошая идея, а низкие рейтинги могут привести к тому, что кофейня потеряет посетителей и разорится.
  • Стоимость чашки капучино должна быть в среднем от 170 до 175 рублей. Такая цена позволит сохранять конкурентоспособность, так как она не будет в низком центовом сегменте и не будет в высоком.

Презентация¶

Презентация: https://disk.yandex.ru/i/ZYk0bEmLTNhGJA